from direct.showbase.DirectObject import DirectObject
from pandac.PandaModules import *
import direct.directbase.DirectStart

from direct.interval.IntervalGlobal import *
from direct.interval.LerpInterval import LerpPosHprInterval

#from ic.interactiveConsole import pandaConsole, INPUT_CONSOLE, INPUT_GUI, OUTPUT_PYTHON, OUTPUT_IRC

class World(DirectObject):
  def __init__(self):
    # INPUT_CONSOLE: enables the commandline text input
    # INPUT_GUI: create the panda3d interface for the console
    # OUTPUT_PYTHON: enables the python code executer
    # OUTPUT_IRC: enables the irc backend
    #self.console = pandaConsole(INPUT_CONSOLE|INPUT_GUI|OUTPUT_PYTHON, locals())
    
    # start out hidden
    #self.console.toggle()
    
    #self.accept("escape", self.console.toggle)
    
    #base.disableMouse()
    
    colour = (0,0,0)
    self.fog = Fog("Scene-wide exponential Fog object")
    self.fog.setColor(*colour)
    self.fog.setExpDensity(0.002)
    base.setBackgroundColor(*colour)
    self.foggy = True
    render.setFog(self.fog)
    self.accept('f', self.toggleFog)
    
    self.moveCameraToDefaultPos()
    '''
    base.disableMouse()
    base.camera.setPos(30,-100,10)
    base.camera.lookAt(10,10,30)
    mat=Mat4(camera.getMat())
    mat.invertInPlace()
    base.mouseInterfaceNode.setMat(mat)
    base.enableMouse()
    '''
    
    soundBgr = loader.loadSfx('sounds/ambient.mp3')
    soundBgr.play()
    

    #Glowing
    self.enableGlow()

  def _cleanupCameraMove(self):
    mat=Mat4(camera.getMat())
    mat.invertInPlace()
    base.mouseInterfaceNode.setMat(mat)
    base.enableMouse()

  def moveCamera(self, pos, hpr):
    s = Sequence()
    s.append(Func(base.disableMouse))
    s.append(LerpPosHprInterval(base.camera, 1.0, pos, hpr))
    s.append(Func(self._cleanupCameraMove))
    s.start()

  def moveCameraToDefaultPos(self):
    self.moveCamera(Point3(18.6024, -97.0097, 17.9589),
                    VBase3(-1.86565, 0.561654, -0.233307))

  def toggleFog(self):
    if self.foggy:
      render.clearFog()
    else:
      render.setFog(self.fog)
    self.foggy = not self.foggy
    
  def enableGlow(self):
    #create the shader that will determime what parts of the scene will glow
    glowShader=Shader.load("shaders/glowShader.sha")


    # create the glow buffer. This buffer renders like a normal scene,
    # except that only the glowing materials should show up nonblack.
    glowBuffer=base.win.makeTextureBuffer("Glow scene", 512, 512)
    glowBuffer.setSort(-3)
    glowBuffer.setClearColor(Vec4(0,0,0,1))

    # We have to attach a camera to the glow buffer. The glow camera
    # must have the same frustum as the main camera. As long as the aspect
    # ratios match, the rest will take care of itself.
    glowCamera=base.makeCamera(glowBuffer, lens=base.cam.node().getLens())

    # Tell the glow camera to use the glow shader
    tempnode = NodePath(PandaNode("temp node"))
    tempnode.setShader(glowShader)
    glowCamera.node().setInitialState(tempnode.getState())

    # set up the pipeline: from glow scene to blur x to blur y to main window.
    blurXBuffer=makeFilterBuffer(glowBuffer,  "Blur X", -2, "shaders/XBlurShader.sha")
    blurYBuffer=makeFilterBuffer(blurXBuffer, "Blur Y", -1, "shaders/YBlurShader.sha")
    finalcard = blurYBuffer.getTextureCard()
    finalcard.reparentTo(render2d)
    finalcard.setAttrib(ColorBlendAttrib.make(ColorBlendAttrib.MAdd))


#This function is responsible for setting up the two blur filters.
#It just makes a temp Buffer, puts a screen aligned card, and then sets
#the appropiate shader to do all the work. Gaussian blurs are decomposable
#into a two-pass algorithm which is faster than the equivalent one-pass
#algorithm, so we do it in two passes. The full explanation (for math buffs)
#can be found in the article above
def makeFilterBuffer(srcbuffer, name, sort, prog):
    blurBuffer=base.win.makeTextureBuffer(name, 512, 512)
    blurBuffer.setSort(sort)
    blurBuffer.setClearColor(Vec4(1,0,0,1))
    blurCamera=base.makeCamera2d(blurBuffer)
    blurScene=NodePath("new Scene")
    blurCamera.node().setScene(blurScene)
    shader = Shader.load(prog)
    card = srcbuffer.getTextureCard()
    card.reparentTo(blurScene)
    card.setShader(shader)
    return blurBuffer